In this document, we summarize the logic, structure, and results of
the analyses.
- Effect of ecological factors on nematode load.
- Phylogenetic signal of encapsulations in the Naesiotus
radiation.
- Analysis of nematode sequenced DNA.
1. Effect of ecological factors on nematode load
We investigate the impact of various ecological factors on nematode
load in snails within the Naesiotus radiation. Species exhibit
differences in shell brightness, which are linked to distinct habitats
and island age (Kraemer et al. 2019). It is hypothesized that snails
evolve brighter shells to mitigate abiotic pressure from insolation,
aiding in thermoregulation. Kraemer et al. (2019) documented that snails
on older islands and in humid habitats typically have darker shells that
blend with their backgrounds, potentially due to biotic pressure from
predatory birds. This suggests a trade-off between abiotic and biotic
selection forces influencing shell brightness, with other factors such
as snail behavior playing a role in this complex dynamic.
We hypothesize that snail behavior, microhabitat, and island
characteristics influence nematode load in snail shells. Nematodes may
be more abundant and diverse in ground-level and humid habitats. The age
of an island correlates with community maturity, which could affect
nematode abundance and diversity in various ways. For example, older
islands may support a higher diversity of nematode species due to
increased time for coevolution and specialization in infecting snails.
Additionally, larger island areas might promote nematode diversity by
providing a wider range of habitats. While it is unclear whether shell
brightness directly affects the snail’s capacity for nematode
encapsulation, it is plausible given that both are influenced by the
shell’s chemical structure and composition.
We test whether snails’ mean brightness, microhabitat, vegetation
zone, island age and area predict the variation in encapsulated nematode
loads.
We use three different datasets:
- 04april24_datalab: contains the nematode
load, island age and area data - nematode
counts/island data per individual, per snail species.
- kraemer2019_brightness_scores: contains the
brightness and habitat data - brightness scores and
habitat per individual, per snail species.
- GPS RAD snails: contains the vegeation
zone and habitat data - vegetation zone and habitat per
individual, per snail species.
In all scripts, there are steps to correct and match names between
the datasets.
The script raw_data. computes data
plots:
Fig 1. Nematode counts by categories on each
species and island
Fig 2. (A) shows the mean brightness for each
snail species in the X asis and the nematode counts in the Y axis, with
individual counts in black and means for each species in red. (B) shows
the data for habitat for each snail species, and the black points show
the mean load. (C) as in B for vegetation zone data. (D) Nematode counts
and mean for the different species within each island as a function of
island age. (E) as in D for island area. (E) boxplot showing the
distribution of mean load data of the species within each island
We first run a model for each predictor separately, and then
build a join model combining them all.
1.1. Load ~ Brightness
47 \(i\) species with load data and
23 \(k\) species with brightness
data
We assume a negative slope, with brighter shells showing less
load, based on our intuition of the system and the raw data
Brightness Model
\[
\log(\text{brightness}_k) \sim \mathcal{N}(\mu_{\text{bright},
\text{species}_k}, \sigma_{\text{bright}})
\]
Nematode Load Model
\[
\lambda_j = \alpha + \beta \mu_{\text{bright}, j}
\] \[
\text{load}_i \sim \text{Poisson}(\exp(\lambda_{\text{species}_i}))
\]
Stan
data {
int<lower=0> N_nem; // Number of observations for nematode load
int<lower=0> N_bright; // Number of observations for brightness
array[N_nem] int<lower=0, upper=100> load; // Nematode load counts
vector[N_bright] brightness; // Brightness scores
int<lower=0> N_sp_nem; // Number of species in the nematode data
// int<lower=0> N_sp_bright; // Number of species in the brightness data
array[N_nem] int<lower=1, upper=N_sp_nem> species_i; // New species id for load dataset
array[N_bright] int<lower=1, upper=N_sp_nem> species_k; // New species id for brightness dataset
}
transformed data{
vector[N_bright] log_brightness;
log_brightness = log(brightness);
}
parameters {
real intercept;
real<upper=0> slope_bright;
vector[N_sp_nem] mu_bright; // Mean brightness for each species
real<lower=0> sigma_bright; // Standard deviation of brightness for each species
}
model {
vector[N_sp_nem] lambda;
// Priors
intercept ~ normal(0, 1);
slope_bright ~ normal(0, 1);
mu_bright ~ normal(5, 2);
sigma_bright ~ exponential(1);
// Model brightness
log_brightness ~ normal(mu_bright[species_k], sigma_bright);
// Model nematode load
lambda = intercept + slope_bright * mu_bright;
load ~ poisson_log(lambda[species_i]); //T[ ,100];
}
generated quantities {
array[N_bright] real predicted_brightness; // Predicted brightness
array[N_nem] int predicted_load; // Predicted nematode load
for (n in 1:N_nem) {
predicted_load[n] = poisson_log_rng(intercept + slope_bright * mu_bright[species_i[n]]);
}
for (b in 1:N_bright) {
predicted_brightness[b] = exp(normal_rng(mu_bright[species_k[b]], sigma_bright));
}
}
Posteriors
Fig 3. Parameter posterior distributions for
Load ~ brightness model
Predictive accuracy
Fig 4. Predictive accuracy for Load ~ brightness
model. (A) Predictions for load data. (B) Predictions for brightness
data
1.2. Load ~ habitat
47 \(i\) species with load data and
30 \(h\) species with brightness data
We assume a negative slope, with arboreous snails showing less
load (terrestrial coded as 0, arboreous as 1)
Habitat Model
\[
\text{habitat}_h \sim
\text{Bernoulli}(\text{habitat\_prob}_{\text{species}_h})
\]
Nematode Load Model
\[
\lambda_j = \text{intercept} + \text{slope\_habitat} \times
\text{habitat\_prob}
\] \[
\text{load}_i \sim \text{Poisson}(\exp(\lambda_{\text{species}_i}))
\]
Stan
data {
int<lower=0> N_nem; // Number of observations for nematode load
int<lower=0> N_habitat; // Number of observations for habitat
array[N_nem] int<lower=0, upper=100> load; // Nematode load counts
array[N_habitat] int<lower=0, upper=1> habitat; // Habitat: 0 for terrestrial, 1 for arboreal
int<lower=0> N_sp_nem; // Number of species in the nematode data
array[N_nem] int<lower=1, upper=N_sp_nem> species_i; // New species id for load dataset
array[N_habitat] int<lower=1, upper=N_sp_nem> species_h; // New species id for habitat dataset
}
parameters {
real intercept;
real<upper=0> slope_habitat;
vector<lower=0, upper=1>[N_sp_nem] habitat_prob; // Habitat probability for each species
}
model {
vector[N_sp_nem] lambda;
// Priors
intercept ~ normal(0, 1);
slope_habitat ~ normal(0, 1);
habitat_prob ~ beta(2, 2); // Prior for habitat probabilities
// Model habitat
habitat ~ bernoulli(habitat_prob[species_h]);
// Model nematode load
lambda = intercept + slope_habitat * habitat_prob;
load ~ poisson_log(lambda[species_i]);
}
generated quantities {
array[N_habitat] real predicted_habitat; // Predicted habitat probabilities
array[N_nem] int predicted_load; // Predicted nematode load
for (n in 1:N_nem) {
predicted_load[n] = poisson_log_rng(intercept + slope_habitat * habitat_prob[species_i[n]]);
}
for (h in 1:N_habitat) {
predicted_habitat[h] = bernoulli_rng(habitat_prob[species_h[h]]);
}
}
Posteriors
Fig 5. Parameter posterior distributions for
Load ~ habitat model
Predictive accuracy
Fig 6. Predictive accuracy for Load ~ habitat
model. (A) Predictions for load data. (B) Predictions for habitat
data
1.3. Load ~ vegetation zone
47 \(i\) species with load data and
26 \(v\) species with brightness data
We assume a negative slope, with snails inhabiting arid zones
showing less load (humid coded as 0, arid as 1)
Vegetation Zone Model
\[
\text{vegetation}_v \sim
\text{Bernoulli}(\text{vegetation\_prob}_{\text{species}_v})
\]
Nematode Load Model
\[
\lambda_j = \text{intercept} + \text{slope\_vegetation} \times
\text{vegetation\_prob}
\] \[
\text{load}_i \sim \text{Poisson}(\exp(\lambda_{\text{species}_i}))
\]
Stan
data {
int<lower=0> N_nem; // Number of observations for nematode load
int<lower=0> N_veg; // Number of observations for vegetation zone
array[N_nem] int<lower=0, upper=100> load; // Nematode load counts
array[N_veg] int<lower=0, upper=1> vegetation; // Vegetation zone: 0 for humid, 1 for arid
int<lower=0> N_sp_nem; // Number of species in the nematode data
array[N_nem] int<lower=1, upper=N_sp_nem> species_i; // New species id for load dataset
array[N_veg] int<lower=1, upper=N_sp_nem> species_v; // New species id for vegetation dataset
}
parameters {
real intercept;
real<upper=0> slope_vegetation;
vector<lower=0, upper=1>[N_sp_nem] vegetation_prob; // Vegetation probability for each species
}
model {
vector[N_sp_nem] lambda;
// Priors
intercept ~ normal(0, 1);
slope_vegetation ~ normal(0, 1);
vegetation_prob ~ beta(2, 2); // Prior for vegetation probabilities
// Model vegetation zone
vegetation ~ bernoulli(vegetation_prob[species_v]);
// Model nematode load
lambda = intercept + slope_vegetation * vegetation_prob;
load ~ poisson_log(lambda[species_i]);
}
generated quantities {
array[N_veg] real predicted_vegetation; // Predicted vegetation probabilities
array[N_nem] int predicted_load; // Predicted nematode load
for (n in 1:N_nem) {
predicted_load[n] = poisson_log_rng(intercept + slope_vegetation * vegetation_prob[species_i[n]]);
}
for (v in 1:N_veg) {
predicted_vegetation[v] = bernoulli_rng(vegetation_prob[species_v[v]]);
}
}
Posteriors
Predictive accuracy
Fig 8. Predictive accuracy for Load ~ vegetation
model. (A) Predictions for load data. (B) Predictions for vegetation
data
1.3. Load ~ island age and area
Nematode Load Model
\[
\lambda_i = \text{intercept} + \text{slope\_age} \times
\text{island\_age}_i + \text{slope\_area} \times
\log(\text{island\_area}_i)
\] \[
\text{load}_i \sim \text{Poisson}(\exp(\lambda_i))
\]
Stan
data {
int<lower=0> N_nem; // Number of observations
array[N_nem] int<lower=0, upper=100> load; // Nematode load counts
vector[N_nem] island_age; // Island age for each observation
vector[N_nem] island_area; // Island area for each observation
}
transformed data {
vector[N_nem] log_island_area;
log_island_area = log(island_area); // Log-transform island area
}
parameters {
real intercept;
real slope_age; // Slope for island age
real slope_area; // Slope for log-transformed island area
}
model {
vector[N_nem] lambda;
// Priors
intercept ~ normal(0, 1);
slope_age ~ normal(0, 1);
slope_area ~ normal(0, 1);
// Linear predictor
lambda = intercept + slope_age * island_age + slope_area * log_island_area;
// Model
load ~ poisson_log(lambda);
}
generated quantities {
array[N_nem] int predicted_load; // Predicted nematode load
for (n in 1:N_nem) {
predicted_load[n] = poisson_log_rng(intercept + slope_age * island_age[n] + slope_area * log_island_area[n]);
}
}
Posteriors
Predictive accuracy
Fig 10. Predictive accuracy for Load ~ island
age + island area model
2. Phylogenetic signal of encapsulations in the Naesiotus
radiation
Departuring from the most recent tree built using RAD seq, we use the
RAD database to add the tip names:
Fig X. K statistic value in null
distribution
We prune it to keep only the species we analyzed that match the
current names:
Fig X. K statistic value in null
distribution
We use the phytools package to test for phylogenetic
signal.
Klomberg’s K
Phylogenetic signal K : 2.21319 MLE(sig2) :
6.27678e-05 logL(sig2) : -36.6456 P-value (based on 1000 randomizations)
: 0.001
Fig X. K statistic value in null
distribution
Plotting the trait value and branches using
contMap() function:
Fig X. K statistic value in null
distribution
LS0tDQp0aXRsZTogIkd1aWRlIGFuYWx5c2lzIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KSW4gdGhpcyBkb2N1bWVudCwgd2Ugc3VtbWFyaXplIHRoZSBsb2dpYywgc3RydWN0dXJlLCBhbmQgcmVzdWx0cyBvZiB0aGUgYW5hbHlzZXMuDQoNCjEuICBFZmZlY3Qgb2YgZWNvbG9naWNhbCBmYWN0b3JzIG9uIG5lbWF0b2RlIGxvYWQuDQoyLiAgUGh5bG9nZW5ldGljIHNpZ25hbCBvZiBlbmNhcHN1bGF0aW9ucyBpbiB0aGUgTmFlc2lvdHVzIHJhZGlhdGlvbi4NCjMuICBBbmFseXNpcyBvZiBuZW1hdG9kZSBzZXF1ZW5jZWQgRE5BLg0KDQo8YnI+IDxicj4NCg0KIyAxLiBFZmZlY3Qgb2YgZWNvbG9naWNhbCBmYWN0b3JzIG9uIG5lbWF0b2RlIGxvYWQNCg0KPGJyPiA8YnI+DQoNCldlIGludmVzdGlnYXRlIHRoZSBpbXBhY3Qgb2YgdmFyaW91cyBlY29sb2dpY2FsIGZhY3RvcnMgb24gbmVtYXRvZGUgbG9hZCBpbiBzbmFpbHMgd2l0aGluIHRoZSBOYWVzaW90dXMgcmFkaWF0aW9uLiBTcGVjaWVzIGV4aGliaXQgZGlmZmVyZW5jZXMgaW4gc2hlbGwgYnJpZ2h0bmVzcywgd2hpY2ggYXJlIGxpbmtlZCB0byBkaXN0aW5jdCBoYWJpdGF0cyBhbmQgaXNsYW5kIGFnZSAoS3JhZW1lciBldCBhbC4gMjAxOSkuIEl0IGlzIGh5cG90aGVzaXplZCB0aGF0IHNuYWlscyBldm9sdmUgYnJpZ2h0ZXIgc2hlbGxzIHRvIG1pdGlnYXRlIGFiaW90aWMgcHJlc3N1cmUgZnJvbSBpbnNvbGF0aW9uLCBhaWRpbmcgaW4gdGhlcm1vcmVndWxhdGlvbi4gS3JhZW1lciBldCBhbC4gKDIwMTkpIGRvY3VtZW50ZWQgdGhhdCBzbmFpbHMgb24gb2xkZXIgaXNsYW5kcyBhbmQgaW4gaHVtaWQgaGFiaXRhdHMgdHlwaWNhbGx5IGhhdmUgZGFya2VyIHNoZWxscyB0aGF0IGJsZW5kIHdpdGggdGhlaXIgYmFja2dyb3VuZHMsIHBvdGVudGlhbGx5IGR1ZSB0byBiaW90aWMgcHJlc3N1cmUgZnJvbSBwcmVkYXRvcnkgYmlyZHMuIFRoaXMgc3VnZ2VzdHMgYSB0cmFkZS1vZmYgYmV0d2VlbiBhYmlvdGljIGFuZCBiaW90aWMgc2VsZWN0aW9uIGZvcmNlcyBpbmZsdWVuY2luZyBzaGVsbCBicmlnaHRuZXNzLCB3aXRoIG90aGVyIGZhY3RvcnMgc3VjaCBhcyBzbmFpbCBiZWhhdmlvciBwbGF5aW5nIGEgcm9sZSBpbiB0aGlzIGNvbXBsZXggZHluYW1pYy4NCg0KV2UgaHlwb3RoZXNpemUgdGhhdCBzbmFpbCBiZWhhdmlvciwgbWljcm9oYWJpdGF0LCBhbmQgaXNsYW5kIGNoYXJhY3RlcmlzdGljcyBpbmZsdWVuY2UgbmVtYXRvZGUgbG9hZCBpbiBzbmFpbCBzaGVsbHMuIE5lbWF0b2RlcyBtYXkgYmUgbW9yZSBhYnVuZGFudCBhbmQgZGl2ZXJzZSBpbiBncm91bmQtbGV2ZWwgYW5kIGh1bWlkIGhhYml0YXRzLiBUaGUgYWdlIG9mIGFuIGlzbGFuZCBjb3JyZWxhdGVzIHdpdGggY29tbXVuaXR5IG1hdHVyaXR5LCB3aGljaCBjb3VsZCBhZmZlY3QgbmVtYXRvZGUgYWJ1bmRhbmNlIGFuZCBkaXZlcnNpdHkgaW4gdmFyaW91cyB3YXlzLiBGb3IgZXhhbXBsZSwgb2xkZXIgaXNsYW5kcyBtYXkgc3VwcG9ydCBhIGhpZ2hlciBkaXZlcnNpdHkgb2YgbmVtYXRvZGUgc3BlY2llcyBkdWUgdG8gaW5jcmVhc2VkIHRpbWUgZm9yIGNvZXZvbHV0aW9uIGFuZCBzcGVjaWFsaXphdGlvbiBpbiBpbmZlY3Rpbmcgc25haWxzLiBBZGRpdGlvbmFsbHksIGxhcmdlciBpc2xhbmQgYXJlYXMgbWlnaHQgcHJvbW90ZSBuZW1hdG9kZSBkaXZlcnNpdHkgYnkgcHJvdmlkaW5nIGEgd2lkZXIgcmFuZ2Ugb2YgaGFiaXRhdHMuIFdoaWxlIGl0IGlzIHVuY2xlYXIgd2hldGhlciBzaGVsbCBicmlnaHRuZXNzIGRpcmVjdGx5IGFmZmVjdHMgdGhlIHNuYWlsJ3MgY2FwYWNpdHkgZm9yIG5lbWF0b2RlIGVuY2Fwc3VsYXRpb24sIGl0IGlzIHBsYXVzaWJsZSBnaXZlbiB0aGF0IGJvdGggYXJlIGluZmx1ZW5jZWQgYnkgdGhlIHNoZWxsJ3MgY2hlbWljYWwgc3RydWN0dXJlIGFuZCBjb21wb3NpdGlvbi4NCg0KV2UgdGVzdCB3aGV0aGVyIHNuYWlscycgbWVhbiBicmlnaHRuZXNzLCBtaWNyb2hhYml0YXQsIHZlZ2V0YXRpb24gem9uZSwgaXNsYW5kIGFnZSBhbmQgYXJlYSBwcmVkaWN0IHRoZSB2YXJpYXRpb24gaW4gZW5jYXBzdWxhdGVkIG5lbWF0b2RlIGxvYWRzLg0KDQpXZSB1c2UgdGhyZWUgZGlmZmVyZW50IGRhdGFzZXRzOg0KDQotICAgKiowNGFwcmlsMjRfZGF0YWxhYioqOiBjb250YWlucyB0aGUgbmVtYXRvZGUgKmxvYWQqLCAqaXNsYW5kIGFnZSBhbmQgYXJlYSogZGF0YSAtIG5lbWF0b2RlIGNvdW50cy9pc2xhbmQgZGF0YSBwZXIgaW5kaXZpZHVhbCwgcGVyIHNuYWlsIHNwZWNpZXMuDQotICAgKiprcmFlbWVyMjAxOV9icmlnaHRuZXNzX3Njb3JlcyoqOiBjb250YWlucyB0aGUgKmJyaWdodG5lc3MqIGFuZCAqaGFiaXRhdCogZGF0YSAtIGJyaWdodG5lc3Mgc2NvcmVzIGFuZCBoYWJpdGF0IHBlciBpbmRpdmlkdWFsLCBwZXIgc25haWwgc3BlY2llcy4NCi0gICAqKkdQUyBSQUQgc25haWxzKio6IGNvbnRhaW5zIHRoZSAqdmVnZWF0aW9uIHpvbmUqIGFuZCAqaGFiaXRhdCogZGF0YSAtIHZlZ2V0YXRpb24gem9uZSBhbmQgaGFiaXRhdCBwZXIgaW5kaXZpZHVhbCwgcGVyIHNuYWlsIHNwZWNpZXMuDQoNCj4gSW4gYWxsIHNjcmlwdHMsIHRoZXJlIGFyZSBzdGVwcyB0byBjb3JyZWN0IGFuZCBtYXRjaCBuYW1lcyBiZXR3ZWVuIHRoZSBkYXRhc2V0cy4NCg0KVGhlIHNjcmlwdCBbcmF3X2RhdGEuXXtzdHlsZT0iY29sb3I6Ymx1ZSJ9IGNvbXB1dGVzIGRhdGEgcGxvdHM6DQoNCiFbRmlnIDEuIE5lbWF0b2RlIGNvdW50cyBieSBjYXRlZ29yaWVzIG9uIGVhY2ggc3BlY2llcyBhbmQgaXNsYW5kXShkX291dHB1dC9maWd1cmVzL3Jhd19kYXRhL2xvYWRfaXNsYW5kX3NwcC5wbmcpDQoNCiFbRmlnIDIuIChBKSBzaG93cyB0aGUgbWVhbiBicmlnaHRuZXNzIGZvciBlYWNoIHNuYWlsIHNwZWNpZXMgaW4gdGhlIFggYXNpcyBhbmQgdGhlIG5lbWF0b2RlIGNvdW50cyBpbiB0aGUgWSBheGlzLCB3aXRoIGluZGl2aWR1YWwgY291bnRzIGluIGJsYWNrIGFuZCBtZWFucyBmb3IgZWFjaCBzcGVjaWVzIGluIHJlZC4gKEIpIHNob3dzIHRoZSBkYXRhIGZvciBoYWJpdGF0IGZvciBlYWNoIHNuYWlsIHNwZWNpZXMsIGFuZCB0aGUgYmxhY2sgcG9pbnRzIHNob3cgdGhlIG1lYW4gbG9hZC4gKEMpIGFzIGluIEIgZm9yIHZlZ2V0YXRpb24gem9uZSBkYXRhLiAoRCkgTmVtYXRvZGUgY291bnRzIGFuZCBtZWFuIGZvciB0aGUgZGlmZmVyZW50IHNwZWNpZXMgd2l0aGluIGVhY2ggaXNsYW5kIGFzIGEgZnVuY3Rpb24gb2YgaXNsYW5kIGFnZS4gKEUpIGFzIGluIEQgZm9yIGlzbGFuZCBhcmVhLiAoRSkgYm94cGxvdCBzaG93aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgbWVhbiBsb2FkIGRhdGEgb2YgdGhlIHNwZWNpZXMgd2l0aGluIGVhY2ggaXNsYW5kXShkX291dHB1dC9maWd1cmVzL3Jhd19kYXRhL3Bsb3RzX2xvYWRfZWNvbC5wbmcpDQoNCjxicj4gDQo8YnI+DQoNCioqV2UgZmlyc3QgcnVuIGEgbW9kZWwgZm9yIGVhY2ggcHJlZGljdG9yIHNlcGFyYXRlbHksIGFuZCB0aGVuIGJ1aWxkIGEgam9pbiBtb2RlbCBjb21iaW5pbmcgdGhlbSBhbGwuKioNCg0KPGJyPg0KPGJyPg0KDQojIyAxLjEuIExvYWQgfiBCcmlnaHRuZXNzDQoNCjxicj4gDQo8YnI+DQoNCj4gNDcgJGkkIHNwZWNpZXMgd2l0aCBsb2FkIGRhdGEgYW5kIDIzICRrJCBzcGVjaWVzIHdpdGggYnJpZ2h0bmVzcyBkYXRhDQoNCj4gKipXZSBhc3N1bWUgYSBuZWdhdGl2ZSBzbG9wZSwgd2l0aCBicmlnaHRlciBzaGVsbHMgc2hvd2luZyBsZXNzIGxvYWQsIGJhc2VkIG9uIG91ciBpbnR1aXRpb24gb2YgdGhlIHN5c3RlbSBhbmQgdGhlIHJhdyBkYXRhKioNCg0KPGJyPiANCjxicj4NCg0KIyMjIEJyaWdodG5lc3MgTW9kZWwNCg0KJCQgDQpcbG9nKFx0ZXh0e2JyaWdodG5lc3N9X2spIFxzaW0gXG1hdGhjYWx7Tn0oXG11X3tcdGV4dHticmlnaHR9LCBcdGV4dHtzcGVjaWVzfV9rfSwgXHNpZ21hX3tcdGV4dHticmlnaHR9fSkNCiQkDQoNCiMjIyBOZW1hdG9kZSBMb2FkIE1vZGVsDQoNCiQkIA0KXGxhbWJkYV9qID0gXGFscGhhICsgXGJldGEgXG11X3tcdGV4dHticmlnaHR9LCBqfQ0KJCQgJCQgDQpcdGV4dHtsb2FkfV9pIFxzaW0gXHRleHR7UG9pc3Nvbn0oXGV4cChcbGFtYmRhX3tcdGV4dHtzcGVjaWVzfV9pfSkpDQokJA0KDQoNCjxicj4gDQo8YnI+DQoNCiMjIyBTdGFuDQoNCjxicj4gDQo8YnI+DQoNCmBgYCBzdGFuDQpkYXRhIHsNCiAgaW50PGxvd2VyPTA+IE5fbmVtOyAgICAgICAgICAgICAgIC8vIE51bWJlciBvZiBvYnNlcnZhdGlvbnMgZm9yIG5lbWF0b2RlIGxvYWQNCiAgaW50PGxvd2VyPTA+IE5fYnJpZ2h0OyAgICAgICAgICAgIC8vIE51bWJlciBvZiBvYnNlcnZhdGlvbnMgZm9yIGJyaWdodG5lc3MNCiAgYXJyYXlbTl9uZW1dIGludDxsb3dlcj0wLCB1cHBlcj0xMDA+IGxvYWQ7ICAvLyBOZW1hdG9kZSBsb2FkIGNvdW50cw0KICB2ZWN0b3JbTl9icmlnaHRdIGJyaWdodG5lc3M7ICAgICAgIC8vIEJyaWdodG5lc3Mgc2NvcmVzDQogIGludDxsb3dlcj0wPiBOX3NwX25lbTsgICAgICAgICAgICAgLy8gTnVtYmVyIG9mIHNwZWNpZXMgaW4gdGhlIG5lbWF0b2RlIGRhdGENCiAgLy8gaW50PGxvd2VyPTA+IE5fc3BfYnJpZ2h0OyAgICAgICAgICAvLyBOdW1iZXIgb2Ygc3BlY2llcyBpbiB0aGUgYnJpZ2h0bmVzcyBkYXRhDQogIGFycmF5W05fbmVtXSBpbnQ8bG93ZXI9MSwgdXBwZXI9Tl9zcF9uZW0+IHNwZWNpZXNfaTsgICAvLyBOZXcgc3BlY2llcyBpZCBmb3IgbG9hZCBkYXRhc2V0DQogIGFycmF5W05fYnJpZ2h0XSBpbnQ8bG93ZXI9MSwgdXBwZXI9Tl9zcF9uZW0+IHNwZWNpZXNfazsgLy8gTmV3IHNwZWNpZXMgaWQgZm9yIGJyaWdodG5lc3MgZGF0YXNldA0KfQ0KDQp0cmFuc2Zvcm1lZCBkYXRhew0KICANCiAgdmVjdG9yW05fYnJpZ2h0XSBsb2dfYnJpZ2h0bmVzczsNCiAgbG9nX2JyaWdodG5lc3MgPSBsb2coYnJpZ2h0bmVzcyk7DQogIA0KfQ0KDQoNCnBhcmFtZXRlcnMgew0KICByZWFsIGludGVyY2VwdDsNCiAgcmVhbDx1cHBlcj0wPiBzbG9wZV9icmlnaHQ7DQogIHZlY3RvcltOX3NwX25lbV0gbXVfYnJpZ2h0OyAgICAgICAvLyBNZWFuIGJyaWdodG5lc3MgZm9yIGVhY2ggc3BlY2llcw0KICByZWFsPGxvd2VyPTA+IHNpZ21hX2JyaWdodDsgLy8gU3RhbmRhcmQgZGV2aWF0aW9uIG9mIGJyaWdodG5lc3MgZm9yIGVhY2ggc3BlY2llcw0KfQ0KDQptb2RlbCB7DQogIHZlY3RvcltOX3NwX25lbV0gbGFtYmRhOw0KICANCiAgLy8gUHJpb3JzDQogIGludGVyY2VwdCB+IG5vcm1hbCgwLCAxKTsNCiAgc2xvcGVfYnJpZ2h0IH4gbm9ybWFsKDAsIDEpOw0KICBtdV9icmlnaHQgfiBub3JtYWwoNSwgMik7DQogIHNpZ21hX2JyaWdodCB+IGV4cG9uZW50aWFsKDEpOw0KICANCiAgLy8gTW9kZWwgYnJpZ2h0bmVzcw0KICBsb2dfYnJpZ2h0bmVzcyB+IG5vcm1hbChtdV9icmlnaHRbc3BlY2llc19rXSwgc2lnbWFfYnJpZ2h0KTsNCiAgDQogIC8vIE1vZGVsIG5lbWF0b2RlIGxvYWQNCiAgbGFtYmRhID0gaW50ZXJjZXB0ICsgc2xvcGVfYnJpZ2h0ICogbXVfYnJpZ2h0Ow0KICBsb2FkIH4gcG9pc3Nvbl9sb2cobGFtYmRhW3NwZWNpZXNfaV0pOyAvL1RbICwxMDBdOw0KfQ0KDQpnZW5lcmF0ZWQgcXVhbnRpdGllcyB7DQogIGFycmF5W05fYnJpZ2h0XSByZWFsIHByZWRpY3RlZF9icmlnaHRuZXNzOyAgLy8gUHJlZGljdGVkIGJyaWdodG5lc3MNCiAgYXJyYXlbTl9uZW1dIGludCBwcmVkaWN0ZWRfbG9hZDsgIC8vIFByZWRpY3RlZCBuZW1hdG9kZSBsb2FkDQogIA0KICANCiAgDQogIGZvciAobiBpbiAxOk5fbmVtKSB7DQogICAgcHJlZGljdGVkX2xvYWRbbl0gPSBwb2lzc29uX2xvZ19ybmcoaW50ZXJjZXB0ICsgc2xvcGVfYnJpZ2h0ICogbXVfYnJpZ2h0W3NwZWNpZXNfaVtuXV0pOw0KICB9DQogIA0KICANCiAgZm9yIChiIGluIDE6Tl9icmlnaHQpIHsNCiAgICBwcmVkaWN0ZWRfYnJpZ2h0bmVzc1tiXSA9IGV4cChub3JtYWxfcm5nKG11X2JyaWdodFtzcGVjaWVzX2tbYl1dLCBzaWdtYV9icmlnaHQpKTsNCiAgfQ0KICANCn0NCmBgYA0KPGJyPiANCjxicj4NCg0KIyMjIyBQb3N0ZXJpb3JzDQoNCjxicj4NCjxicj4NCg0KDQohW0ZpZyAzLiBQYXJhbWV0ZXIgcG9zdGVyaW9yIGRpc3RyaWJ1dGlvbnMgZm9yIExvYWQgfiBicmlnaHRuZXNzIG1vZGVsXShkX291dHB1dC9maWd1cmVzL3Bvc3Rlcmlvcl9wYXJzL2JyaWdodF9uZWdzbG9wZS5wbmcpDQoNCg0KPGJyPg0KPGJyPg0KDQojIyMjIFByZWRpY3RpdmUgYWNjdXJhY3kNCg0KPGJyPiANCjxicj4NCg0KIVtGaWcgNC4gUHJlZGljdGl2ZSBhY2N1cmFjeSBmb3IgTG9hZCB+IGJyaWdodG5lc3MgbW9kZWwuIChBKSBQcmVkaWN0aW9ucyBmb3IgbG9hZCBkYXRhLiAoQikgUHJlZGljdGlvbnMgZm9yIGJyaWdodG5lc3MgZGF0YV0oZF9vdXRwdXQvZmlndXJlcy9wcmVkaWN0aW9ucy9wcGNfbG9hZF9icmlnaHRfbmVnLnBuZykNCg0KDQoNCjxicj4gDQo8YnI+DQo8YnI+DQoNCiMjIDEuMi4gTG9hZCB+IGhhYml0YXQNCg0KPGJyPg0KPGJyPg0KDQo+IDQ3ICRpJCBzcGVjaWVzIHdpdGggbG9hZCBkYXRhIGFuZCAzMCAkaCQgc3BlY2llcyB3aXRoIGJyaWdodG5lc3MgZGF0YQ0KPiAqKldlIGFzc3VtZSBhIG5lZ2F0aXZlIHNsb3BlLCB3aXRoIGFyYm9yZW91cyBzbmFpbHMgc2hvd2luZyBsZXNzIGxvYWQgKHRlcnJlc3RyaWFsIGNvZGVkIGFzIDAsIGFyYm9yZW91cyBhcyAxKSoqDQoNCjxicj4NCg0KIyMjIyBIYWJpdGF0IE1vZGVsDQpcWyANClx0ZXh0e2hhYml0YXR9X2ggXHNpbSBcdGV4dHtCZXJub3VsbGl9KFx0ZXh0e2hhYml0YXRcX3Byb2J9X3tcdGV4dHtzcGVjaWVzfV9ofSkNClxdDQoNCiMjIyMgTmVtYXRvZGUgTG9hZCBNb2RlbA0KXFsgDQpcbGFtYmRhX2ogPSBcdGV4dHtpbnRlcmNlcHR9ICsgXHRleHR7c2xvcGVcX2hhYml0YXR9IFx0aW1lcyBcdGV4dHtoYWJpdGF0XF9wcm9ifQ0KXF0NClxbIA0KXHRleHR7bG9hZH1faSBcc2ltIFx0ZXh0e1BvaXNzb259KFxleHAoXGxhbWJkYV97XHRleHR7c3BlY2llc31faX0pKQ0KXF0NCg0KDQojIyMgU3Rhbg0KDQpgYGAgc3Rhbg0KZGF0YSB7DQogIGludDxsb3dlcj0wPiBOX25lbTsgICAgICAgICAgICAgICAvLyBOdW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGZvciBuZW1hdG9kZSBsb2FkDQogIGludDxsb3dlcj0wPiBOX2hhYml0YXQ7ICAgICAgICAgICAvLyBOdW1iZXIgb2Ygb2JzZXJ2YXRpb25zIGZvciBoYWJpdGF0DQogIGFycmF5W05fbmVtXSBpbnQ8bG93ZXI9MCwgdXBwZXI9MTAwPiBsb2FkOyAgLy8gTmVtYXRvZGUgbG9hZCBjb3VudHMNCiAgYXJyYXlbTl9oYWJpdGF0XSBpbnQ8bG93ZXI9MCwgdXBwZXI9MT4gaGFiaXRhdDsgLy8gSGFiaXRhdDogMCBmb3IgdGVycmVzdHJpYWwsIDEgZm9yIGFyYm9yZWFsDQogIGludDxsb3dlcj0wPiBOX3NwX25lbTsgICAgICAgICAgICAgLy8gTnVtYmVyIG9mIHNwZWNpZXMgaW4gdGhlIG5lbWF0b2RlIGRhdGENCiAgYXJyYXlbTl9uZW1dIGludDxsb3dlcj0xLCB1cHBlcj1OX3NwX25lbT4gc3BlY2llc19pOyAgIC8vIE5ldyBzcGVjaWVzIGlkIGZvciBsb2FkIGRhdGFzZXQNCiAgYXJyYXlbTl9oYWJpdGF0XSBpbnQ8bG93ZXI9MSwgdXBwZXI9Tl9zcF9uZW0+IHNwZWNpZXNfaDsgLy8gTmV3IHNwZWNpZXMgaWQgZm9yIGhhYml0YXQgZGF0YXNldA0KfQ0KDQpwYXJhbWV0ZXJzIHsNCiAgcmVhbCBpbnRlcmNlcHQ7DQogIHJlYWw8dXBwZXI9MD4gc2xvcGVfaGFiaXRhdDsNCiAgdmVjdG9yPGxvd2VyPTAsIHVwcGVyPTE+W05fc3BfbmVtXSBoYWJpdGF0X3Byb2I7ICAvLyBIYWJpdGF0IHByb2JhYmlsaXR5IGZvciBlYWNoIHNwZWNpZXMNCn0NCg0KbW9kZWwgew0KICB2ZWN0b3JbTl9zcF9uZW1dIGxhbWJkYTsNCiAgDQogIC8vIFByaW9ycw0KICBpbnRlcmNlcHQgfiBub3JtYWwoMCwgMSk7DQogIHNsb3BlX2hhYml0YXQgfiBub3JtYWwoMCwgMSk7DQogIGhhYml0YXRfcHJvYiB+IGJldGEoMiwgMik7ICAvLyBQcmlvciBmb3IgaGFiaXRhdCBwcm9iYWJpbGl0aWVzDQogIA0KICAvLyBNb2RlbCBoYWJpdGF0DQogIGhhYml0YXQgfiBiZXJub3VsbGkoaGFiaXRhdF9wcm9iW3NwZWNpZXNfaF0pOw0KICANCiAgLy8gTW9kZWwgbmVtYXRvZGUgbG9hZA0KICBsYW1iZGEgPSBpbnRlcmNlcHQgKyBzbG9wZV9oYWJpdGF0ICogaGFiaXRhdF9wcm9iOw0KICBsb2FkIH4gcG9pc3Nvbl9sb2cobGFtYmRhW3NwZWNpZXNfaV0pOw0KfQ0KDQpnZW5lcmF0ZWQgcXVhbnRpdGllcyB7DQogIGFycmF5W05faGFiaXRhdF0gcmVhbCBwcmVkaWN0ZWRfaGFiaXRhdDsgIC8vIFByZWRpY3RlZCBoYWJpdGF0IHByb2JhYmlsaXRpZXMNCiAgYXJyYXlbTl9uZW1dIGludCBwcmVkaWN0ZWRfbG9hZDsgIC8vIFByZWRpY3RlZCBuZW1hdG9kZSBsb2FkDQogIA0KICBmb3IgKG4gaW4gMTpOX25lbSkgew0KICAgIHByZWRpY3RlZF9sb2FkW25dID0gcG9pc3Nvbl9sb2dfcm5nKGludGVyY2VwdCArIHNsb3BlX2hhYml0YXQgKiBoYWJpdGF0X3Byb2Jbc3BlY2llc19pW25dXSk7DQogIH0NCiAgDQogIGZvciAoaCBpbiAxOk5faGFiaXRhdCkgew0KICAgIHByZWRpY3RlZF9oYWJpdGF0W2hdID0gYmVybm91bGxpX3JuZyhoYWJpdGF0X3Byb2Jbc3BlY2llc19oW2hdXSk7DQogIH0NCn0NCmBgYA0KDQoNCiMjIyMgUG9zdGVyaW9ycw0KDQo8YnI+DQo8YnI+DQoNCg0KIVtGaWcgNS4gUGFyYW1ldGVyIHBvc3RlcmlvciBkaXN0cmlidXRpb25zIGZvciBMb2FkIH4gaGFiaXRhdCBtb2RlbF0oZF9vdXRwdXQvZmlndXJlcy9wb3N0ZXJpb3JfcGFycy9wb3N0ZXJpb3JfaGFiaXRhdC5wbmcpDQoNCg0KPGJyPg0KPGJyPg0KDQoNCiMjIyMgUHJlZGljdGl2ZSBhY2N1cmFjeQ0KDQo8YnI+IA0KPGJyPg0KDQohW0ZpZyA2LiBQcmVkaWN0aXZlIGFjY3VyYWN5IGZvciBMb2FkIH4gaGFiaXRhdCBtb2RlbC4gKEEpIFByZWRpY3Rpb25zIGZvciBsb2FkIGRhdGEuIChCKSBQcmVkaWN0aW9ucyBmb3IgaGFiaXRhdCBkYXRhXShkX291dHB1dC9maWd1cmVzL3ByZWRpY3Rpb25zL3BwY19sb2FkX2hhYl9uZWcucG5nKQ0KDQoNCg0KPGJyPiANCjxicj4NCjxicj4NCg0KIyMgMS4zLiBMb2FkIH4gdmVnZXRhdGlvbiB6b25lDQoNCjxicj4NCjxicj4NCg0KPiA0NyAkaSQgc3BlY2llcyB3aXRoIGxvYWQgZGF0YSBhbmQgMjYgJHYkIHNwZWNpZXMgd2l0aCBicmlnaHRuZXNzIGRhdGENCj4gKipXZSBhc3N1bWUgYSBuZWdhdGl2ZSBzbG9wZSwgd2l0aCBzbmFpbHMgaW5oYWJpdGluZyBhcmlkIHpvbmVzIHNob3dpbmcgbGVzcyBsb2FkIChodW1pZCBjb2RlZCBhcyAwLCBhcmlkIGFzIDEpKioNCg0KPGJyPg0KDQojIyMjIFZlZ2V0YXRpb24gWm9uZSBNb2RlbA0KXFsgDQpcdGV4dHt2ZWdldGF0aW9ufV92IFxzaW0gXHRleHR7QmVybm91bGxpfShcdGV4dHt2ZWdldGF0aW9uXF9wcm9ifV97XHRleHR7c3BlY2llc31fdn0pDQpcXQ0KDQojIyMjIE5lbWF0b2RlIExvYWQgTW9kZWwNClxbIA0KXGxhbWJkYV9qID0gXHRleHR7aW50ZXJjZXB0fSArIFx0ZXh0e3Nsb3BlXF92ZWdldGF0aW9ufSBcdGltZXMgXHRleHR7dmVnZXRhdGlvblxfcHJvYn0NClxdDQpcWyANClx0ZXh0e2xvYWR9X2kgXHNpbSBcdGV4dHtQb2lzc29ufShcZXhwKFxsYW1iZGFfe1x0ZXh0e3NwZWNpZXN9X2l9KSkNClxdDQoNCg0KIyMjIFN0YW4NCg0KYGBgIHN0YW4NCmRhdGEgew0KICBpbnQ8bG93ZXI9MD4gTl9uZW07ICAgICAgICAgICAgICAgLy8gTnVtYmVyIG9mIG9ic2VydmF0aW9ucyBmb3IgbmVtYXRvZGUgbG9hZA0KICBpbnQ8bG93ZXI9MD4gTl92ZWc7ICAgICAgICAgICAgICAgLy8gTnVtYmVyIG9mIG9ic2VydmF0aW9ucyBmb3IgdmVnZXRhdGlvbiB6b25lDQogIGFycmF5W05fbmVtXSBpbnQ8bG93ZXI9MCwgdXBwZXI9MTAwPiBsb2FkOyAgLy8gTmVtYXRvZGUgbG9hZCBjb3VudHMNCiAgYXJyYXlbTl92ZWddIGludDxsb3dlcj0wLCB1cHBlcj0xPiB2ZWdldGF0aW9uOyAvLyBWZWdldGF0aW9uIHpvbmU6IDAgZm9yIGh1bWlkLCAxIGZvciBhcmlkDQogIGludDxsb3dlcj0wPiBOX3NwX25lbTsgICAgICAgICAgICAgLy8gTnVtYmVyIG9mIHNwZWNpZXMgaW4gdGhlIG5lbWF0b2RlIGRhdGENCiAgYXJyYXlbTl9uZW1dIGludDxsb3dlcj0xLCB1cHBlcj1OX3NwX25lbT4gc3BlY2llc19pOyAgIC8vIE5ldyBzcGVjaWVzIGlkIGZvciBsb2FkIGRhdGFzZXQNCiAgYXJyYXlbTl92ZWddIGludDxsb3dlcj0xLCB1cHBlcj1OX3NwX25lbT4gc3BlY2llc192OyAvLyBOZXcgc3BlY2llcyBpZCBmb3IgdmVnZXRhdGlvbiBkYXRhc2V0DQp9DQoNCnBhcmFtZXRlcnMgew0KICByZWFsIGludGVyY2VwdDsNCiAgcmVhbDx1cHBlcj0wPiBzbG9wZV92ZWdldGF0aW9uOw0KICB2ZWN0b3I8bG93ZXI9MCwgdXBwZXI9MT5bTl9zcF9uZW1dIHZlZ2V0YXRpb25fcHJvYjsgIC8vIFZlZ2V0YXRpb24gcHJvYmFiaWxpdHkgZm9yIGVhY2ggc3BlY2llcw0KfQ0KDQptb2RlbCB7DQogIHZlY3RvcltOX3NwX25lbV0gbGFtYmRhOw0KICANCiAgLy8gUHJpb3JzDQogIGludGVyY2VwdCB+IG5vcm1hbCgwLCAxKTsNCiAgc2xvcGVfdmVnZXRhdGlvbiB+IG5vcm1hbCgwLCAxKTsNCiAgdmVnZXRhdGlvbl9wcm9iIH4gYmV0YSgyLCAyKTsgIC8vIFByaW9yIGZvciB2ZWdldGF0aW9uIHByb2JhYmlsaXRpZXMNCiAgDQogIC8vIE1vZGVsIHZlZ2V0YXRpb24gem9uZQ0KICB2ZWdldGF0aW9uIH4gYmVybm91bGxpKHZlZ2V0YXRpb25fcHJvYltzcGVjaWVzX3ZdKTsNCiAgDQogIC8vIE1vZGVsIG5lbWF0b2RlIGxvYWQNCiAgbGFtYmRhID0gaW50ZXJjZXB0ICsgc2xvcGVfdmVnZXRhdGlvbiAqIHZlZ2V0YXRpb25fcHJvYjsNCiAgbG9hZCB+IHBvaXNzb25fbG9nKGxhbWJkYVtzcGVjaWVzX2ldKTsNCn0NCg0KZ2VuZXJhdGVkIHF1YW50aXRpZXMgew0KICBhcnJheVtOX3ZlZ10gcmVhbCBwcmVkaWN0ZWRfdmVnZXRhdGlvbjsgIC8vIFByZWRpY3RlZCB2ZWdldGF0aW9uIHByb2JhYmlsaXRpZXMNCiAgYXJyYXlbTl9uZW1dIGludCBwcmVkaWN0ZWRfbG9hZDsgIC8vIFByZWRpY3RlZCBuZW1hdG9kZSBsb2FkDQogIA0KICBmb3IgKG4gaW4gMTpOX25lbSkgew0KICAgIHByZWRpY3RlZF9sb2FkW25dID0gcG9pc3Nvbl9sb2dfcm5nKGludGVyY2VwdCArIHNsb3BlX3ZlZ2V0YXRpb24gKiB2ZWdldGF0aW9uX3Byb2Jbc3BlY2llc19pW25dXSk7DQogIH0NCiAgDQogIGZvciAodiBpbiAxOk5fdmVnKSB7DQogICAgcHJlZGljdGVkX3ZlZ2V0YXRpb25bdl0gPSBiZXJub3VsbGlfcm5nKHZlZ2V0YXRpb25fcHJvYltzcGVjaWVzX3Zbdl1dKTsNCiAgfQ0KfQ0KDQpgYGANCg0KDQojIyMjIFBvc3RlcmlvcnMNCg0KPGJyPg0KPGJyPg0KDQoNCiFbRmlnIDcuIFBhcmFtZXRlciBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9ucyBmb3IgTG9hZCB+IHZlZ2V0YXRpb24gbW9kZWxdKGRfb3V0cHV0L2ZpZ3VyZXMvcG9zdGVyaW9yX3BhcnMvcG9zdGVyaW9yX3ZlZ2V0YXRpb24ucG5nKQ0KPGJyPg0KPGJyPg0KDQoNCg0KIyMjIyBQcmVkaWN0aXZlIGFjY3VyYWN5DQoNCjxicj4gDQo8YnI+DQoNCiFbRmlnIDguIFByZWRpY3RpdmUgYWNjdXJhY3kgZm9yIExvYWQgfiB2ZWdldGF0aW9uIG1vZGVsLiAoQSkgUHJlZGljdGlvbnMgZm9yIGxvYWQgZGF0YS4gKEIpIFByZWRpY3Rpb25zIGZvciB2ZWdldGF0aW9uIGRhdGFdKGRfb3V0cHV0L2ZpZ3VyZXMvcHJlZGljdGlvbnMvcHBjX2xvYWRfdmVnX25lZy5wbmcpDQoNCg0KDQo8YnI+IA0KPGJyPg0KPGJyPg0KDQoNCiMjIDEuMy4gTG9hZCB+IGlzbGFuZCBhZ2UgYW5kIGFyZWENCg0KIyMjIyBOZW1hdG9kZSBMb2FkIE1vZGVsDQoNClxbIA0KXGxhbWJkYV9pID0gXHRleHR7aW50ZXJjZXB0fSArIFx0ZXh0e3Nsb3BlXF9hZ2V9IFx0aW1lcyBcdGV4dHtpc2xhbmRcX2FnZX1faSArIFx0ZXh0e3Nsb3BlXF9hcmVhfSBcdGltZXMgXGxvZyhcdGV4dHtpc2xhbmRcX2FyZWF9X2kpDQpcXQ0KXFsgDQpcdGV4dHtsb2FkfV9pIFxzaW0gXHRleHR7UG9pc3Nvbn0oXGV4cChcbGFtYmRhX2kpKQ0KXF0NCg0KIyMjIFN0YW4NCg0KYGBgIHN0YW4NCmRhdGEgew0KICBpbnQ8bG93ZXI9MD4gTl9uZW07ICAgICAgICAgICAgICAgICAgICAgIC8vIE51bWJlciBvZiBvYnNlcnZhdGlvbnMNCiAgYXJyYXlbTl9uZW1dIGludDxsb3dlcj0wLCB1cHBlcj0xMDA+IGxvYWQ7ICAvLyBOZW1hdG9kZSBsb2FkIGNvdW50cw0KICB2ZWN0b3JbTl9uZW1dIGlzbGFuZF9hZ2U7ICAgICAgICAgICAgICAgLy8gSXNsYW5kIGFnZSBmb3IgZWFjaCBvYnNlcnZhdGlvbg0KICB2ZWN0b3JbTl9uZW1dIGlzbGFuZF9hcmVhOyAgICAgICAgICAgIC8vIElzbGFuZCBhcmVhIGZvciBlYWNoIG9ic2VydmF0aW9uDQp9DQoNCnRyYW5zZm9ybWVkIGRhdGEgew0KICB2ZWN0b3JbTl9uZW1dIGxvZ19pc2xhbmRfYXJlYTsNCiAgbG9nX2lzbGFuZF9hcmVhID0gbG9nKGlzbGFuZF9hcmVhKTsgIC8vIExvZy10cmFuc2Zvcm0gaXNsYW5kIGFyZWENCn0NCg0KcGFyYW1ldGVycyB7DQogIHJlYWwgaW50ZXJjZXB0Ow0KICByZWFsIHNsb3BlX2FnZTsgICAgICAgICAgICAgICAgICAgICAgLy8gU2xvcGUgZm9yIGlzbGFuZCBhZ2UNCiAgcmVhbCBzbG9wZV9hcmVhOyAgICAgICAgICAgICAgICAgICAgIC8vIFNsb3BlIGZvciBsb2ctdHJhbnNmb3JtZWQgaXNsYW5kIGFyZWENCn0NCg0KbW9kZWwgew0KICB2ZWN0b3JbTl9uZW1dIGxhbWJkYTsNCiAgDQogIC8vIFByaW9ycw0KICBpbnRlcmNlcHQgfiBub3JtYWwoMCwgMSk7DQogIHNsb3BlX2FnZSB+IG5vcm1hbCgwLCAxKTsNCiAgc2xvcGVfYXJlYSB+IG5vcm1hbCgwLCAxKTsNCiAgDQogIC8vIExpbmVhciBwcmVkaWN0b3INCiAgbGFtYmRhID0gaW50ZXJjZXB0ICsgc2xvcGVfYWdlICogaXNsYW5kX2FnZSArIHNsb3BlX2FyZWEgKiBsb2dfaXNsYW5kX2FyZWE7DQogIA0KICAvLyBNb2RlbA0KICBsb2FkIH4gcG9pc3Nvbl9sb2cobGFtYmRhKTsgDQp9DQoNCmdlbmVyYXRlZCBxdWFudGl0aWVzIHsNCiAgYXJyYXlbTl9uZW1dIGludCBwcmVkaWN0ZWRfbG9hZDsgIC8vIFByZWRpY3RlZCBuZW1hdG9kZSBsb2FkDQogIA0KICBmb3IgKG4gaW4gMTpOX25lbSkgew0KICAgIHByZWRpY3RlZF9sb2FkW25dID0gcG9pc3Nvbl9sb2dfcm5nKGludGVyY2VwdCArIHNsb3BlX2FnZSAqIGlzbGFuZF9hZ2Vbbl0gKyBzbG9wZV9hcmVhICogbG9nX2lzbGFuZF9hcmVhW25dKTsNCiAgfQ0KfQ0KDQpgYGANCg0KDQojIyMjIFBvc3RlcmlvcnMNCg0KPGJyPg0KPGJyPg0KDQoNCiFbRmlnIDkuIFBhcmFtZXRlciBwb3N0ZXJpb3IgZGlzdHJpYnV0aW9ucyBmb3IgTG9hZCB+IHZlZ2V0YXRpb24gbW9kZWxdKGRfb3V0cHV0L2ZpZ3VyZXMvcG9zdGVyaW9yX3BhcnMvcG9zdGVyaW9yX2lzbGFuZC5wbmcpDQo8YnI+DQo8YnI+DQoNCiMjIyMgUHJlZGljdGl2ZSBhY2N1cmFjeQ0KDQo8YnI+IA0KPGJyPg0KDQohW0ZpZyAxMC4gUHJlZGljdGl2ZSBhY2N1cmFjeSBmb3IgTG9hZCB+IGlzbGFuZCBhZ2UgKyBpc2xhbmQgYXJlYSBtb2RlbF0oZF9vdXRwdXQvZmlndXJlcy9wcmVkaWN0aW9ucy9wcGNfbG9hZF9hZ2VhcmVhLnBuZykNCg0KDQoNCjxicj4gDQo8YnI+DQo8YnI+DQoNCg0KDQojIDIuIFBoeWxvZ2VuZXRpYyBzaWduYWwgb2YgZW5jYXBzdWxhdGlvbnMgaW4gdGhlIE5hZXNpb3R1cyByYWRpYXRpb24NCg0KPGJyPg0KPGJyPg0KDQoNCkRlcGFydHVyaW5nIGZyb20gdGhlIG1vc3QgcmVjZW50IHRyZWUgYnVpbHQgdXNpbmcgUkFEIHNlcSwgd2UgdXNlIHRoZSBSQUQgZGF0YWJhc2UgdG8gYWRkIHRoZSB0aXAgbmFtZXM6DQoNCjxicj4NCg0KIVtGaWcgWC4gSyBzdGF0aXN0aWMgdmFsdWUgaW4gbnVsbCBkaXN0cmlidXRpb25dKGRfb3V0cHV0L2ZpZ3VyZXMvcGh5bG8vdHJlZV9waGlsbGlwcy5wbmcpDQoNCjxicj4NCjxicj4NCg0KDQpXZSBwcnVuZSBpdCB0byBrZWVwIG9ubHkgdGhlIHNwZWNpZXMgd2UgYW5hbHl6ZWQgdGhhdCBtYXRjaCB0aGUgY3VycmVudCBuYW1lczoNCg0KPGJyPg0KDQohW0ZpZyBYLiBLIHN0YXRpc3RpYyB2YWx1ZSBpbiBudWxsIGRpc3RyaWJ1dGlvbl0oZF9vdXRwdXQvZmlndXJlcy9waHlsby9wcnVuZWRfdHJlZS5wbmcpDQoNCjxicj4NCjxicj4NCg0KPiBXZSB1c2UgdGhlICoqcGh5dG9vbHMqKiBwYWNrYWdlIHRvIHRlc3QgZm9yIHBoeWxvZ2VuZXRpYyBzaWduYWwuDQoNCiMjIEtsb21iZXJnJ3MgSw0KDQo8YnI+DQoNClBoeWxvZ2VuZXRpYyBzaWduYWwgSyA6ICoqMi4yMTMxOSoqIA0KTUxFKHNpZzIpIDogNi4yNzY3OGUtMDUgDQpsb2dMKHNpZzIpIDogLTM2LjY0NTYgDQpQLXZhbHVlIChiYXNlZCBvbiAxMDAwIHJhbmRvbWl6YXRpb25zKSA6ICoqMC4wMDEqKiANCg0KPGJyPg0KDQoNCiFbRmlnIFguIEsgc3RhdGlzdGljIHZhbHVlIGluIG51bGwgZGlzdHJpYnV0aW9uXShkX291dHB1dC9maWd1cmVzL3BoeWxvL2tfc3RhdGlzdGljLnBuZykNCg0KPGJyPg0KDQoNClBsb3R0aW5nIHRoZSB0cmFpdCB2YWx1ZSBhbmQgYnJhbmNoZXMgdXNpbmcgKipjb250TWFwKCkqKiBmdW5jdGlvbjoNCg0KPGJyPg0KDQoNCiFbRmlnIFguIEsgc3RhdGlzdGljIHZhbHVlIGluIG51bGwgZGlzdHJpYnV0aW9uXShkX291dHB1dC9maWd1cmVzL3BoeWxvL3BoeWxvX2JyYW5jaF9jb2xvci5wbmcpDQo=